package tianrun.ziguan.api.calculate.config.service.sync.handler;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import tianrun.ziguan.api.calculate.config.dto.request.CalLabelConfigVO;
import tianrun.ziguan.api.calculate.config.dto.request.ExpressionVO;
import tianrun.ziguan.api.calculate.config.dto.request.TAssetExpressionVO;
import tianrun.ziguan.api.calculate.config.dto.response.TAssetCalLabelConfigVO;
import tianrun.ziguan.api.calculate.config.entity.TAssetCalLabelConfig;
import tianrun.ziguan.api.calculate.config.entity.TAssetExpression;
import tianrun.ziguan.api.calculate.config.entity.TCalLabelConfig;
import tianrun.ziguan.api.calculate.config.entity.TExpression;
import tianrun.ziguan.api.calculate.config.entity.base.*;
import tianrun.ziguan.api.calculate.config.service.asset.callabel.ITAssetCalLabelConfigService;
import tianrun.ziguan.api.calculate.config.service.asset.experssion.ITAssetExpressionService;
import tianrun.ziguan.api.calculate.config.service.cal.label.ITCalLabelConfigService;
import tianrun.ziguan.api.calculate.config.service.expression.ITExpressionService;
import tianrun.ziguan.api.calculate.config.utils.MyBeanUtil;
import tianrun.ziguan.api.calculate.config.utils.Setter;
import tianrun.ziguan.api.common.util.ListUtil;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class AbstractSyncHandler implements SyncHandler{


    protected <V extends BaseAssetInstance, Y extends BaseTemplateInstance, X extends BaseAssetModule> List<V> getNewTargetInstances(List<V> targetInstancesList, List<Y> sourceInstanceList, X targetModule, Class<V> vClass) {
        List<V> assetInstances = Lists.newArrayList();
        Map<Long, V> targetByTemplateInstanceIdMap = targetInstancesList.stream().filter(v -> Objects.nonNull(v.getTemplateInstanceId())).collect(Collectors.toMap(V::getTemplateInstanceId, Function.identity(),(v, v2) -> v));
        Map<String, V> targetByCalLabelMap = targetInstancesList.stream().filter(v -> Objects.nonNull(v.unique())).collect(Collectors.toMap(V::unique, Function.identity()));
        sourceInstanceList.forEach(sourceInstance -> {
            V targetInstance;
            try {
                targetInstance = targetByCalLabelMap.getOrDefault(sourceInstance.unique(), targetByTemplateInstanceIdMap.getOrDefault(sourceInstance.getId(), vClass.getDeclaredConstructor().newInstance()));
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                     NoSuchMethodException e) {
                throw new IllegalArgumentException("没有该Class的无参构造:" + vClass.getName());
            }
            //新增的Module现在没有id,出去需要重新赋值
            MyBeanUtil.doCopy(sourceInstance, targetInstance,
                    Setter.set(targetInstance::setId, targetInstance.getId()),
                    Setter.set(targetInstance::setModuleId, targetModule.getId())
                    , Setter.set(targetInstance::setTemplateInstanceId, sourceInstance.getId()));
            assetInstances.add(targetInstance);
        });
        return assetInstances;
    }

    protected <V extends BaseTemplateInstance, X extends BaseTemplateModule> List<V> getNewTargetTemplateInstances(List<V> targetInstancesList, List<V> sourceInstanceList, X targetModule, Class<V> vClass) {
        List<V> assetInstances = Lists.newArrayList();
        Map<String, V> targetByCalLabelMap = targetInstancesList.stream().filter(v -> Objects.nonNull(v.unique())).collect(Collectors.toMap(V::unique, Function.identity()));
        sourceInstanceList.forEach(sourceInstance -> {
            V targetInstance;
            try {
                targetInstance = targetByCalLabelMap.getOrDefault(sourceInstance.unique(), vClass.getDeclaredConstructor().newInstance());
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                     NoSuchMethodException e) {
                throw new IllegalArgumentException("没有该Class的无参构造:" + vClass.getName());
            }
            //新增的Module现在没有id,出去需要重新赋值
            MyBeanUtil.doCopy(sourceInstance, targetInstance,
                    Setter.set(targetInstance::setId, targetInstance.getId()),
                    Setter.set(targetInstance::setModuleId, targetModule.getId()));
            assetInstances.add(targetInstance);
        });
        return assetInstances;
    }

    /**
     * 模板表达式和虚拟变量通用操作
     */
    protected <V extends BaseTemplateInstance> void labelConfigAndExpressionHandleByTemplate(List<CalLabelConfigVO> sourceLabelConfigs, List<ExpressionVO> sourceExpressions, List<CalLabelConfigVO> assetCalLabelConfigs, List<ExpressionVO> assetExpressions, List<V> saveInstances, String instanceTableName, ITExpressionService expressionService, ITCalLabelConfigService calLabelConfigService) {


        List<TCalLabelConfig> saveConfigs = calLabelConfigHandle(ListUtil.mapList(sourceLabelConfigs, BaseCalLabelConfig.class::cast),
                ListUtil.mapList(assetCalLabelConfigs, BaseCalLabelConfig.class::cast),
                saveInstances,
                instanceTableName,
                TCalLabelConfig.class
        );
        List<TExpression> saveExpressions = expressionHandle(ListUtil.mapList(sourceExpressions, BaseExpression.class::cast),
                ListUtil.mapList(assetExpressions, BaseExpression.class::cast),
                saveInstances,
                instanceTableName,
                TExpression.class
        );

        expressionService.saveOrUpdateBatch(saveExpressions);
        calLabelConfigService.saveOrUpdateBatch(saveConfigs);
        List<Long> instanceIds = saveInstances.stream().map(V::getId).collect(Collectors.toList());

        //删除多的表达式
        expressionService.remove(Wrappers.
                <TExpression>lambdaQuery().
                in(TExpression::getRelationId, instanceIds).
                in(TExpression::getRelationTable, instanceTableName).
                notIn(TExpression::getId, saveExpressions.stream().map(TExpression::getId).collect(Collectors.toList())));
        //删除多余的配置
        calLabelConfigService.remove(Wrappers.
                <TCalLabelConfig>lambdaQuery().
                in(TCalLabelConfig::getRelationId, instanceIds).
                in(TCalLabelConfig::getRelationTable, instanceTableName).
                notIn(TCalLabelConfig::getId, saveConfigs.stream().map(TCalLabelConfig::getId).collect(Collectors.toList())));
    }


    /**
     * 资产表达式和虚拟变量通用操作
     */
    protected <V extends BaseAssetInstance> void labelConfigAndExpressionHandle(List<CalLabelConfigVO> sourceLabelConfigs, List<ExpressionVO> sourceExpressions, List<TAssetCalLabelConfigVO> assetCalLabelConfigs, List<TAssetExpressionVO> assetExpressions, List<V> saveInstances, String instanceTableName, ITAssetExpressionService assetExpressionService, ITAssetCalLabelConfigService assetCalLabelConfigService) {
        //判断config和表达式
        List<TAssetCalLabelConfig> saveConfigs = calLabelConfigHandle(ListUtil.mapList(sourceLabelConfigs, BaseCalLabelConfig.class::cast),
                ListUtil.mapList(assetCalLabelConfigs, BaseCalLabelConfig.class::cast),
                saveInstances,
                instanceTableName,
                TAssetCalLabelConfig.class
        );
        List<TAssetExpression> saveExpressions = expressionHandle(ListUtil.mapList(sourceExpressions, BaseExpression.class::cast),
                ListUtil.mapList(assetExpressions, BaseExpression.class::cast),
                saveInstances,
                instanceTableName,
                TAssetExpression.class
        );


        assetExpressionService.saveOrUpdateBatch(saveExpressions);
        assetCalLabelConfigService.saveOrUpdateBatch(saveConfigs);
        List<Long> instanceIds = saveInstances.stream().map(V::getId).collect(Collectors.toList());

        //删除多的表达式
        assetExpressionService.remove(Wrappers.
                <TAssetExpression>lambdaQuery().
                in(TAssetExpression::getRelationId, instanceIds).
                in(TAssetExpression::getRelationTable, instanceTableName).
                notIn(TAssetExpression::getId, saveExpressions.stream().map(TAssetExpression::getId).collect(Collectors.toList())));
        //删除多余的配置
        assetCalLabelConfigService.remove(Wrappers.
                <TAssetCalLabelConfig>lambdaQuery().
                in(TAssetCalLabelConfig::getRelationId, instanceIds).
                in(TAssetCalLabelConfig::getRelationTable, instanceTableName).
                notIn(TAssetCalLabelConfig::getId, saveConfigs.stream().map(TAssetCalLabelConfig::getId).collect(Collectors.toList())));
    }

    private <V extends BaseCalLabelConfig, N extends BaseUnique, M extends BaseCalLabelConfig> List<M> calLabelConfigHandle(List<V> sourceLabelConfigs, List<V> targetCalLabelConfigs, List<N> saveInstances, String instanceTableName, Class<M> vClass) {
        Map<String, List<V>> sourceConfigMap = ListUtil.groupList(sourceLabelConfigs, V::getCalLabel);
        Map<String, V> assetCalLabelConfigMap = targetCalLabelConfigs.stream().collect(Collectors.toMap(c -> getCalLabelConfigKey(c.getRelationId(), c.getVirtualLabel(), instanceTableName), Function.identity()));
        ArrayList<V> saveConfigs = Lists.newArrayList();

        saveInstances.forEach(targetInstance -> {
            String calLabel = targetInstance.unique();
            List<V> sourceInstanceLabelConfigs = sourceConfigMap.get(calLabel);
            sourceInstanceLabelConfigs.forEach(sourceLabelConfig -> {

                V target = assetCalLabelConfigMap.getOrDefault(getCalLabelConfigKey(targetInstance.getId(), sourceLabelConfig.getVirtualLabel(), instanceTableName), (V) getClassInstance(vClass));
                MyBeanUtil.doCopy(sourceLabelConfig, target,
                        new Setter<>(target::setId, target.getId()),
                        new Setter<>(target::setRelationId, targetInstance.getId()),
                        new Setter<>(target::setRelationTable, instanceTableName)
                );
                saveConfigs.add(target);
            });
        });
        return ListUtil.mapList(saveConfigs, vClass::cast);
    }

    private <V extends BaseExpression, N extends BaseUnique, M extends BaseExpression> List<M> expressionHandle(List<V> sourceExpressions, List<V> targetExpressions, List<N> saveInstances, String instanceTableName, Class<M> vClass) {
        Map<String, V> sourceExpressMap = sourceExpressions.stream().collect(Collectors.toMap(V::getCalLabel, Function.identity(), (a, b) -> a));
        Map<Long, V> assetExpressionMap = targetExpressions.stream().collect(Collectors.toMap(V::getRelationId, Function.identity(), (a, b) -> a));
        ArrayList<V> saveExpressions = Lists.newArrayList();

        saveInstances.forEach(targetInstance -> {
            String calLabel = targetInstance.unique();
            V sourceExpression = sourceExpressMap.get(calLabel);

            V expression = assetExpressionMap.getOrDefault(targetInstance.getId(), (V) getClassInstance(vClass));
            MyBeanUtil.doCopy(sourceExpression, expression,
                    new Setter<>(expression::setId, expression.getId()),
                    new Setter<>(expression::setRelationId, targetInstance.getId()),
                    new Setter<>(expression::setRelationTable, instanceTableName)
            );
            saveExpressions.add(expression);
        });
        return ListUtil.mapList(saveExpressions, vClass::cast);
    }

    private <V> V getClassInstance(Class<V> vClass) {
        try {
            return vClass.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                 NoSuchMethodException e) {
            throw new IllegalArgumentException("没有该Class的无参构造:" + vClass.getName());
        }
    }

    private String getCalLabelConfigKey(Long relationId, String virtualLabel, String tableName) {
        return relationId + ":" + virtualLabel + ":" + tableName;
    }
}
